/* 观察者模式(observer pattern) 定义对象间的一种一对多的依赖关系，以便当一个对象(被观察者)的状态发生变化的时候，
所有依赖于它的对象(观察者)都会得到通知并自动更新。

本例：通过观察者模式，实现监控分割算法的中间过程，其中算法过程是被观察者(称subject)，监控类是观察者(observer)，
当需要监控的时候，通过被观察者添加监控，就可以查看算法的中间过程。 */

#include <algorithm>
#include <iostream>
#include <memory>
#include <vector>

using namespace std;

class Observer;
class Subject;

#pragma region //观察者模块
class Observer
{
    public:
    virtual void update(const char* msg) =0;
    virtual ~Observer(){};
};

class Debug : public Observer
{
public:
    void update(const char* msg);
    virtual ~Debug(){};
};

void Debug::update(const char* msg)
{
    cout<<"Debug result:"<<msg<<endl;
}

#pragma endregion


#pragma region //被观察者模块
class Subject
{
    public:
    virtual void add_observer(Observer* observer) = 0;
    virtual void remove_observer(Observer* observer) = 0;
    virtual void notify(const char* msg) = 0;
    virtual ~Subject(){};

};

class Segment: public Subject
{
    public:
    
    void add_observer(Observer* observer);
    void remove_observer(Observer* observer);
    void notify(const char* msg);

    void run_alg();

    private:
    void resample_image(){
        cout<<"resample finished."<<endl;
    }

    void normalization(){
        cout<<"normalization finished."<<endl;
    }

    void otsu_threshold(){
        cout<<"otsu threshold finished."<<endl;
    }

    void resample_ref(){
        cout<<"resample ref finished."<<endl;
    }

    vector<Observer*> m_observers;

};

void Segment::add_observer(Observer* observer)
{
    auto it = find(m_observers.cbegin(), m_observers.cend(), observer);
    if (it != m_observers.cend()){
        cout<<"add_observer faild, becouse the observer exist."<<endl;
    }
    else{
        m_observers.push_back(observer);
    }
    
}

void Segment::remove_observer(Observer* observer)
{
    auto it = find(m_observers.cbegin(), m_observers.cend(), observer);
    if(it != m_observers.cend()){
        m_observers.erase(it);
    }
    else{
        cout <<"observer not in list, cannot remove it."<<endl;
    }
}

void Segment::notify(const char* msg)
{
    for(const auto t_elem : m_observers){
        t_elem->update(msg);
    }
}

void Segment::run_alg()
{
    resample_image();
    notify("The result of resample is right.");

    normalization();
    notify("The result of normalization is right.");

    otsu_threshold();
    notify("The result of otsu threshold is right.");

    resample_ref();
    notify("The result of resample ref is right.");

}

#pragma endregion


int main(int argc, char const *argv[])
{
    unique_ptr<Segment> segment_ptr(new Segment());
    unique_ptr<Debug> debug_ptr_01(new Debug());
    unique_ptr<Debug> debug_ptr_02(new Debug());
    unique_ptr<Debug> debug_ptr_03(new Debug());

    // 实际应用中，只需要修改这里就行.
    segment_ptr->add_observer(debug_ptr_01.get());
    segment_ptr->add_observer(debug_ptr_02.get());
    segment_ptr->add_observer(debug_ptr_01.get()); // 测试重复添加观察者
    segment_ptr->remove_observer(debug_ptr_03.get()); // 测试删除不存在的观察者

    segment_ptr->run_alg();

    cout<< "\n\nThe result of no observer." << endl;
    segment_ptr->remove_observer(debug_ptr_01.get());
    segment_ptr->remove_observer(debug_ptr_02.get());
    
    segment_ptr->run_alg();

    
	
	return 0;
}